package com.zian.service.impl;

import cn.hutool.core.util.StrUtil;
import com.zian.common.CommonConstant;
import com.zian.domain.po.SysAdminUser;
import com.zian.domain.po.SysUser;
import com.zian.exception.LoginException;
import com.zian.properties.JwtProperties;
import com.zian.service.ITokenService;
import com.zian.utils.JwtUtil;
import com.zian.utils.RedisUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Service
@RequiredArgsConstructor
public class TokenServiceImpl implements ITokenService {

    private final JwtUtil jwtUtil;

    private final JwtProperties jwtProperties;

    private final RedisUtils redisUtils;

    /**
     * 获取请求头中的token 进行解析
     *
     * @param request
     * @return
     */
    @Override
    public Long parseToken(HttpServletRequest request, Boolean isAdmin) {
        // 1. 获取请求头中token
        String token = request.getHeader(jwtProperties.getTokenName());
        if (StrUtil.isBlank(token)) throw new LoginException("token为空");

        String uuid = "";
        //2. 解析token
        try {
            uuid = jwtUtil.parseJWT(token).getSubject();
        } catch (Exception e) {
            throw new LoginException("token异常");
        }


        // 3. 拿着token 从 redis 中获取用户的信息
        if (isAdmin) {
            // 3.1 管理员，拼接管理员的key , 获取管理员信息
            String tokenKey = CommonConstant.LOGIN_ADMIN_USER_KEY + uuid;
            Serializable cacheUserInfo = redisUtils.getCacheObject(tokenKey);
            if (cacheUserInfo == null) throw new LoginException("登录异常");
            SysAdminUser userInfo = (SysAdminUser) cacheUserInfo;

            // 3.2 根据userId 获取 redis 中缓存的uuid 判断是否和当前的token 是否一致 （实现单点登录）
            String userIdKey = CommonConstant.LOGIN_ADMIN_USERID_KEY + userInfo.getId();
            Serializable cacheObject = redisUtils.getCacheObject(userIdKey);
            if (cacheObject == null) throw new LoginException("登录异常");
            String cacheToken = (String) cacheObject;
            if (!StrUtil.equals(uuid, cacheToken)) throw new LoginException("登录异常");


            // 3.3 刷新token
            refreshToken(userInfo.getExpireTime(), userIdKey, tokenKey);
            return userInfo.getId();
        } else {
            // 3.1 用户，拼接用户的key , 获取用户信息
            String tokenKey = CommonConstant.LOGIN_USER_KEY + uuid;
            Serializable cacheUserInfo = redisUtils.getCacheObject(tokenKey);
            if (cacheUserInfo == null) throw new LoginException("用户登录异常");
            SysUser userInfo = (SysUser) cacheUserInfo;

            // 3.2 根据userId 获取 redis 中缓存的uuid 判断是否和当前的token 是否一致 （实现单点登录）
            String userIdKey = CommonConstant.LOGIN_USERID_KEY + userInfo.getId();
            Serializable cacheObject = redisUtils.getCacheObject(userIdKey);
            if (cacheObject == null) throw new LoginException("登录异常");
            String cacheToken = (String) cacheObject;
            if (!StrUtil.equals(uuid, cacheToken)) throw new LoginException("登录异常");

            // 3.3 刷新token
            refreshToken(userInfo.getExpireTime(), userIdKey, tokenKey);
            return userInfo.getId();
        }

    }

    /**
     * 检查是否要刷新token
     *
     * @param expireTime
     * @param userIdKey
     * @param tokenKey
     */
    private void refreshToken(Date expireTime, String userIdKey, String tokenKey) {

        // 如果 redis 中缓存的用户有效时间不超过 20 分钟，对 redis 缓存的信息进行续期
        if (expireTime.getTime() - System.currentTimeMillis() < 20 * 60 * 1000) {
            redisUtils.expire(userIdKey, jwtProperties.getTtl(), TimeUnit.MINUTES);
            redisUtils.expire(tokenKey, jwtProperties.getTtl(), TimeUnit.MINUTES);
        }
    }
}
